package org.youyee.game.managers
{
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.EventDispatcher;
	import flash.events.TimerEvent;
	import flash.utils.Dictionary;
	import flash.utils.Timer;
	
	import org.youyee.game.displayArea.DisplayMode;
	import org.youyee.game.event.MapObjectEvent;
	import org.youyee.game.interfaces.IDepthItem;
	import org.youyee.game.pathFinding.PathNode;
	
	/**
	 * 深度管理器 
	 * @author youyee
	 * 
	 */	
	public class DepthManager extends EventDispatcher
	{
		/**
		 * 层级刷新的频率 
		 */		
		public static var REFRESH_RATE:int = 300;
		
		private var _items:Vector.<IDepthItem>;
		private var _numItems:int;
		private var _controlLayer:Sprite;
		private var _timer:Timer;
		private var _useRefreshTimer:Boolean;
		private var _depthIndex:int;
		private var _dependency:Dictionary;
		private var _visitedItem:Dictionary;
		private var _sortResult:Array;
		private var _mode:int;
		
		/**
		 * 构造函数 
		 * @param controlLayer 需要被控制的显示容器
		 * @param useRefreshTimer 使用刷新计时器
		 * @param mode 使用的模式
		 * 
		 */		
		public function DepthManager(controlLayer:Sprite, useRefreshTimer:Boolean=true, mode:int=0)
		{
			_numItems = 0;
			_items = new Vector.<IDepthItem>();
			//出于性能考虑，不对此显示容器进行监听
			_controlLayer = controlLayer;
			_useRefreshTimer = useRefreshTimer;
			_timer = new Timer(REFRESH_RATE);
			_mode = mode;
			initListener();
		}
		
		private function initListener():void
		{
			_timer.addEventListener(TimerEvent.TIMER, handleTimer);
			_controlLayer.addEventListener(MapObjectEvent.NEED_REFRESH_DEPTH, handleNeedRefreshDepth);
			_controlLayer.addEventListener(MapObjectEvent.OBJECT_DESTROY, handleItemDestroy);
		}
		
		private function handleItemDestroy(e:MapObjectEvent):void
		{
			var item:IDepthItem = e.target as IDepthItem;
			item && removeItem(item);
			item = null;
		}
		
		private function removeListener():void
		{
			_timer && _timer.removeEventListener(TimerEvent.TIMER, handleTimer);
			_controlLayer && _controlLayer.removeEventListener(MapObjectEvent.NEED_REFRESH_DEPTH, handleNeedRefreshDepth);
		}
		
		private function handleNeedRefreshDepth(e:MapObjectEvent):void
		{
			//立即中止事件的冒泡，出于性能考虑才写如下的代码，如果需要其他地方监听这个事件，请注释掉下面这一句
			e.stopImmediatePropagation();
			refreshDepth();
		}
		
		private function handleTimer(e:TimerEvent):void
		{
			_numItems && refreshDepth();
		}
		
		/**
		 * 添加一个物体到深度管理器 
		 * @param item 需要被深度管理
		 * @param refreshDepthImmediatly 是否需要立即刷新层级
		 * 
		 */		
		public function addItem(item:IDepthItem, refreshDepthImmediatly:Boolean=false):void
		{
			if (!this._timer)
			{
				return;
			}
			
			this._items.push(item);
			_numItems = this._items.length;
			
			if (!this._timer.running && _useRefreshTimer)
			{
				this._timer.start();
			}
			
			if (refreshDepthImmediatly)
			{
				refreshDepth();
			}
		}
		
		/**
		 * 清除物品 
		 * @param item 从深度管理器移除一个物品
		 * @return 被成功移除的物品
		 * 
		 */		
		public function removeItem(item:IDepthItem):IDepthItem
		{
			//在物品需要移除的时候会保证timer先停止工作
			_timer.stop();
			
			var index:int = _items.indexOf(item);
			
			if (index != -1)
			{
				_items.splice(index, 1);
				_numItems = this._items.length;
				_numItems && _useRefreshTimer && _timer.start();
				return item;
			}
			
			return null;
		}
		
		/**
		 * 刷新层级深度 
		 * 
		 */		
		public function refreshDepth():void
		{
			if (_mode == DisplayMode.MODE_45)
			{
				sortDepth();
			}
			else
			{
				sortNormal();
			}
			
			var zItem:DisplayObject;
			var index:int;
			var numItems:int = _controlLayer.numChildren;
			var len:int = _numItems;
			
			for (var i:int=0; i<len; ++i)
			{
				zItem = _sortResult[i] as DisplayObject;
				
				//确保 zItem 确实存在容器中，这个地方多少有些性能消耗
				if (zItem.parent == _controlLayer)
				{
					index = _controlLayer ? _controlLayer.getChildIndex(zItem) : 0;
					index != i && numItems > index && _controlLayer.setChildIndex(zItem, i);
				}
			}
			
			zItem = null;
		}
		
		private function sortNormal():void
		{
			_sortResult = [];
			
			for (var i:int=0; i<_numItems; ++i)
			{
				_sortResult.push(_items[i]);
			}
			
			_sortResult.sortOn("y", Array.NUMERIC);
		}
		
		private function sortDepth():void
		{
			var len:int = this._numItems;
			var behind:Vector.<IDepthItem>
			var itemA:IDepthItem;
			var itemB:IDepthItem;
			_dependency = new Dictionary();
			var j:int;
			var compareResult:int;
			
			for (var i:int=0; i<len; ++i)
			{
				behind = new Vector.<IDepthItem>();
				itemA = this._items[i];
				
				for (j=0; j<len; ++j)
				{
					itemB = this._items[j];
					if (i != j && compareDepth(itemA, itemB) == 1)
					{
						behind.push(itemB);
					}
				}
				
				_dependency[itemA] = behind; 
			}
			
			//拓扑排序算法
			_sortResult = [];
			_depthIndex = 0;
			_visitedItem = new Dictionary();
			
			for (j=0; j<len; ++j)
			{
				if (!_visitedItem[this._items[j]])
				{
					placeToIndex(this._items[j]);
				}
			}
		}
		
		private function placeToIndex(item:IDepthItem):void
		{
			_visitedItem[item] = true;
			
			var behind:Vector.<IDepthItem> = _dependency[item] as Vector.<IDepthItem>;
			var len:int = behind.length;
			
			for (var i:int=0; i<len; ++i)
			{
				if (!_visitedItem[behind[i]])
				{
					placeToIndex(behind[i]);
				}
			}
			
			_sortResult[_depthIndex] = item;
			++_depthIndex;
		}
		
		private function compareDepth(a:IDepthItem, b:IDepthItem):int
		{
			//对于单格物品走普通的排序对比逻辑
			if (a.areaSize == b.areaSize && a.areaSize == 1)
			{
				return compareZIndex(a, b);
			}
			
			//对于多格物品，进行深度对比排序
			return deepCompare(a, b);
		}
		
		private function deepCompare(a:IDepthItem, b:IDepthItem):int
		{
			var aNode:PathNode = a.pathNode;
			var bNode:PathNode = b.pathNode;
			
			var aItemWidth:int = aNode.x + a.itemWidth;
			var bItemWidth:int = bNode.x + b.itemWidth;
			
			var aItemHeight:int = aNode.y + a.itemHeight;
			var bItemHeight:int = bNode.y + b.itemHeight;
			
			//a物体遮挡b物体
			if (
				(aNode.x < bItemWidth && bNode.y < aNode.y && aItemWidth > bNode.x) || 
				(aNode.x > bNode.x && bItemHeight > aNode.y && aItemHeight > bNode.y) ||
				(aNode.x >= bItemWidth && aNode.y >= bItemHeight)
			)
			{
				aNode = bNode = null;
				return 1; 
			}
			//a物体被b物体遮挡
			else if (
				(aNode.x < bNode.x && bItemHeight > aNode.y && bNode.y < aItemHeight) ||
				(aNode.y < bNode.y && bItemWidth > aNode.x && bNode.x < aItemWidth) ||
				(aItemWidth <= bNode.x && aItemHeight <= bNode.y)
			)
			{
				aNode = bNode = null;
				return -1;
			}
			
			aNode = bNode = null;
			return 0;
		}
		
		private function compareZIndex(a:IDepthItem, b:IDepthItem):int
		{
			var aIndex:int = a.zIndex;
			var bIndex:int = b.zIndex;
			//非争议区域直接比对 zIndex;
			if (aIndex > bIndex)
			{
				return 1;
			}
			else if (aIndex < bIndex)
			{
				return -1;
			}
			
			return 0;
		}
		
		/**
		 * 销毁管理器 
		 * 
		 */		
		public function destroy():void
		{
			if (_timer)
			{
				_timer.stop();
			}
			
			removeListener();
			
			this._controlLayer = null;
			this._items = null;
			this._timer = null;
			this._numItems = 0;
			this._dependency = null;
			this._depthIndex = 0;
			this._sortResult = null;
			this._visitedItem = null;
		}
	}
}